package cn.edu.nju.ws.sview.wyge.relations.datasets;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;

import com.mysql.jdbc.DocsConnectionPropsHelper;

import cn.edu.nju.ws.sview.cache.CooccurCache;
import cn.edu.nju.ws.sview.cache.URIIDCache;
import cn.edu.nju.ws.sview.cache.URILabelCache;
import cn.edu.nju.ws.sview.crawler.Crawler;
import cn.edu.nju.ws.sview.crawler.Element;
import cn.edu.nju.ws.sview.database.DBConnectionFactory;
import cn.edu.nju.ws.sview.database.DBOperations;
import cn.edu.nju.ws.sview.rdf.ResourceFactory;
import cn.edu.nju.ws.sview.rdf.URIResource;
import cn.edu.nju.ws.sview.util.URIUtil;
import cn.edu.nju.ws.sview.views.Entity;
import cn.edu.nju.ws.sview.views.User;
import cn.edu.nju.ws.sview.views.data.EntityManagement;
import cn.edu.nju.ws.sview.views.data.EntityManagement.URIMember;
import cn.edu.nju.ws.sview.wyge.relations.adataset.CustomDataset;
import cn.edu.nju.ws.sview.wyge.relations.adataset.DocumentDataset;
import cn.edu.nju.ws.sview.wyge.relations.index.SearchIndexManager;

/**
 * input hints fetch the popular entities my entities
 * 
 * @author ssgong
 * 
 */
public class DatasetBrowsing {
	   public final static double COOCCUR_SCORE_WEIGHT = EntityManagement.SAMEAS_SCORE_WEIGHT;
	   public final static double GROUP_SCORE_WEIGHT = EntityManagement.GROUP_SCORE_WEIGHT;
	   public final static int RECOMMEND_NUM = 10;

	public static ArrayList<DatasetItem> kw2Datasets(String kw, String lang) {
//		ArrayList<DatasetItem> res = IndexManager.getIndexManager().getDatasetsByTerm(kw, 10);
		ArrayList<DatasetItem> res = SearchIndexManager.getIndexManager().getDatasetsByNameUri(kw, lang, 10);
		return res;
	}
	/**
	 * for dataset_edit.jsp indexSearch
	 * @param kw
	 * @param start
	 * @param length
	 * @param lang
	 * @return
	 */
	public static int kw2DatasetsForDsBuild(String kw, int start, int length, String lang, ArrayList<DatasetItem> result){
		int totalNum = SearchIndexManager.getIndexManager().getDatasetsByContent(kw, lang, start, length, result);
//		System.out.println("inbrowsing:"+totalNum+"|"+result.size());
		return totalNum;
	}
	public static DatasetItem uri2Dataset(String uri, String lang) {
		DatasetItem di = null;
		try {
			Connection con = DBConnectionFactory.getConnection();//.getFalconConnection();
			PreparedStatement selps = con
					.prepareStatement("SELECT id FROM uri where uri = ?");
			PreparedStatement selidps = con
					.prepareStatement("SELECT id FROM rdf_doc where id = ?");//("SELECT uri_id FROM rdf_doc where uri_id = ?");
			selps.setString(1, uri);
			ResultSet selrs = selps.executeQuery();
			if (selrs.next()) {
				int id = selrs.getInt(1);
				selidps.setInt(1, id);
				ResultSet selidrs = selidps.executeQuery();
				if (selidrs.next()) {
					di = new DatasetItem("uri", id, uri);
					di.setShowName(DatasetItem.getShowNameByDatasetID(di, lang));//=====
				}
				selidrs.close();
			}
			selrs.close();
			selps.close();
			selidps.close();
			con.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return di;
	}
	public static void deleteVisit(DatasetItem datasetItem){
		try {
			Connection conn = DBConnectionFactory.getConnection();
			PreparedStatement pstmt = conn.prepareStatement("delete from ds_user_visit where ds_id=? and ds_type=? ");
			pstmt.setInt(1, datasetItem.getId());
			pstmt.setString(2, datasetItem.getGenre());
			pstmt.close();
			conn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	/**
	 * @param start
	 *            起 始位置
	 * @param length
	 *            长度
	 * @return 排序列表（包括bookmark的entity，原始的entity和集合）中从start开始的总共length个元素
	 */
	public static ArrayList<DatasetItem> fetchAll(int start, int length, String lang) {
		ArrayList<DatasetItem> items = new ArrayList<DatasetItem>();
		try {
			Connection conn = DBConnectionFactory.getConnection();
			Statement stmt = conn.createStatement();
			String str = String
					.format("SELECT ds_type,ds_id FROM ds_user_visit where lang='%s' group by ds_type,ds_id order by sum(times_total) desc limit %d, %d",
							lang, start, length);
			ResultSet rs = stmt.executeQuery(str);
			while (rs.next()) {
				String dsType = rs.getString(1);
				int dsId = rs.getInt(2);
//				String name = null;
//				if (dsType.equals("custom")) {
//					name = CustomDataset.getNameByCustomDatasetID(dsId);
//				} else if (dsType.equals("uri")) {
//					try {
//						name = URIResource.getLabel(dsId, lang);//URIIDCache.getInstance().getURI(dsId);
//					} catch (Throwable e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}
//				}
//				items.add(new DatasetItem(dsType, dsId, name));
				items.add(new DatasetItem(dsType, dsId, null));
			}
			rs.close();
			stmt.close();
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return items;
	}

	/**
	 * get the custom datasets in the user's group
	 * 
	 * @param user
	 * @param start
	 * @param length
	 * @return
	 */
	public static ArrayList<DatasetItem> fetchUserAll(String user, int start, int length){//, String lang) {
		ArrayList<DatasetItem> items = new ArrayList<DatasetItem>();
		int userId = User.getUserIdByName(user);
		if (userId < 0)
			return items;
		try {
			User userInstance = new User(user);
			String group_ids = userInstance.getGroups().toString();
			group_ids = group_ids.replace("[", "(");
			group_ids = group_ids.replace("]", ")");
//			System.out.println("watch out! DatasetBrowsing.java groups:"+group_ids);
			Connection conn = DBConnectionFactory.getConnection();
//			Statement stmt = conn.createStatement();
//			ResultSet rs = stmt
//					.executeQuery(String
//							.format("SELECT 'custom', id FROM custom_dataset where user_id = %d and lang = '%s' order by time desc limit  %d, %d",
//									userId, lang, start, length));
//			PreparedStatement pstmt = conn.prepareStatement("SELECT 'custom', id FROM custom_dataset where group_id in "+group_ids+" and lang = ? order by time desc limit  ?, ?");
//			pstmt.setString(1, lang);
//			pstmt.setInt(2, start);
//			pstmt.setInt(3, length);
			PreparedStatement pstmt = conn.prepareStatement("SELECT 'custom', id FROM custom_dataset where group_id in "+group_ids+" order by time desc limit  ?, ?");
			pstmt.setInt(1, start);
			pstmt.setInt(2, length);
			ResultSet rs = pstmt.executeQuery();
			while (rs.next()) {
				String dsType = rs.getString(1);
				int dsId = rs.getInt(2);
//				String name = null;
//				name = CustomDataset.getNameByCustomDatasetID(dsId);
//				System.out.println("name:"+name);
				items.add(new DatasetItem(dsType, dsId, null));//name));
			}
			rs.close();
			pstmt.close();
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return items;
	}
	
	public static ArrayList<DatasetItem> fetchGroupAll(int groupID, int start,
			int length){//, String lang) {
		ArrayList<DatasetItem> items = new ArrayList<DatasetItem>();
		if (groupID < 0)
			return items;
		try {
			Connection conn = DBConnectionFactory.getConnection();
//			PreparedStatement pstmt = conn.prepareStatement("SELECT 'custom', id FROM custom_dataset where group_id=?  and lang = ? order by time desc limit  ?, ?");
//			pstmt.setInt(1, groupID);
//			pstmt.setString(2, lang);
//			pstmt.setInt(3, start);
//			pstmt.setInt(4, length);
			StringBuffer sqlb = new StringBuffer("SELECT 'custom', id FROM custom_dataset where group_id=? order by update_time desc ");
//			PreparedStatement pstmt = conn.prepareStatement("SELECT 'custom', id FROM custom_dataset where group_id=? order by time desc limit  ?, ?");
			if(length>0){
				sqlb.append(String.format("limit %d,%d", start, length));
			}
			PreparedStatement pstmt = conn.prepareStatement(sqlb.toString());
			pstmt.setInt(1, groupID);
//			pstmt.setInt(2, start);
//			pstmt.setInt(3, length);
			ResultSet rs = pstmt.executeQuery();
			while (rs.next()) {
				String dsType = rs.getString(1);
				int dsId = rs.getInt(2);
//				String name = null;
//				name = CustomDataset.getNameByCustomDatasetID(dsId);
//				System.out.println("name:"+name);
				items.add(new DatasetItem(dsType, dsId, null));//name));
			}
			rs.close();
			pstmt.close();
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return items;
	}
	
	public static ArrayList<URIMember> getDatasetMembers(String ds_type, int datasetId, String lang){
		
		ArrayList<URIMember> array = new ArrayList<URIMember>();
		if(ds_type.contentEquals("uri")){
			DocumentDataset docds = DocumentDataset.getInstance(datasetId);
			try {
				array.add(new URIMember(datasetId, docds.getName(), URIResource.getLabel(datasetId, lang)));//URILabelCache.getInstance().getLabel(datasetId, lang)));//docds.getName()));//
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else if(ds_type.contentEquals("custom")){
			try {
				Connection conn = DBConnectionFactory.getConnection();
				PreparedStatement getDocId = conn.prepareStatement("select doc_id from custom_dataset_doc where dataset_id=?");
				PreparedStatement getUri = conn.prepareStatement("select uri from uri where id=?");
				getDocId.setInt(1, datasetId);
				ResultSet idrs = getDocId.executeQuery();
				ResultSet urirs = null;
				while(idrs.next()){
					int id=idrs.getInt(1);
					getUri.setInt(1, id);
					urirs = getUri.executeQuery();
					if(urirs.next()){
						String uri = urirs.getString(1);
						array.add(new URIMember(id, uri,URIResource.getLabel(id, lang)));//URILabelCache.getInstance().getLabel(id, lang)));// uri));//
//						System.out.println("member:"+id+"|"+uri+"|"+URIResource.getLabel(id, lang)+"|");
					}
				}
				urirs.close();
				idrs.close();
				getDocId.close();
				getUri.close();
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return array;
	}
	public static HashSet<Integer> getMembersByDatasetId(int datasetId, String ds_type){
		HashSet<Integer> result = new HashSet<Integer>();
		if(ds_type.contentEquals("uri")){
			result.add(datasetId);
		}else if(ds_type.contentEquals("custom")){
			try {
				Connection conn = DBConnectionFactory.getConnection();
				PreparedStatement pstmt = conn.prepareStatement("select doc_id from custom_dataset_doc where dataset_id=?");
				pstmt.setInt(1, datasetId);
				ResultSet rs = pstmt.executeQuery();
				while(rs.next()){
					result.add(rs.getInt(1));
				}
				rs.close();
				pstmt.close();
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return result;
	}
	public static HashSet<DatasetItem> getRelatedMygroupDataset(String ds_type, int datasetId, int groupID){
		HashSet<DatasetItem> result = new HashSet<DatasetItem>();
		HashSet<Integer> originURIs = new HashSet<Integer>();
		originURIs.addAll(DatasetBrowsing.getMembersByDatasetId(datasetId, ds_type));
//		if(ds_type.contentEquals("uri")){
//			originURIs.add(datasetId);
//		}else{
//			originURIs.addAll(DatasetBrowsing.getMembersByDatasetId(datasetId));
//		}
		try {
			Connection conn = DBConnectionFactory.getConnection();
//			PreparedStatement pstmt = conn.prepareStatement("select id, name from custom_dataset,custom_dataset_doc where dataset_id=id and group_id=? and doc_id=?");
//			pstmt.setInt(1, groupID);
			PreparedStatement pstmt = conn.prepareStatement("select id from custom_dataset,custom_dataset_doc where dataset_id=id and group_id=? and doc_id=?");
			pstmt.setInt(1, groupID);
			ResultSet rs = null;
			for(Integer uid: originURIs){
				pstmt.setInt(2, uid);
				rs = pstmt.executeQuery();
				while(rs.next()){
					int datasetID = rs.getInt(1);
					String type = DatasetItem.CUSTOM_GENRE;
//					String name = rs.getString(2);
					DatasetItem item = new DatasetItem(type, datasetID, null);//, name);
					result.add(item);
				}
			}
			rs.close();
			pstmt.close();
			conn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}
//	public static ArrayList<RecomdDatasetItem> getRecommendDataset(String ds_type, int datasetId, int groupID, String lang){//=========????
	public static ArrayList<RecomdDatasetItem> getRecommendDataset(String ds_type, int datasetId){//, String lang){//=========????
			ArrayList<RecomdDatasetItem> result = new ArrayList<RecomdDatasetItem>();
		   HashSet<Integer> originURIs  = new HashSet<Integer>();
		   originURIs.addAll(DatasetBrowsing.getMembersByDatasetId(datasetId, ds_type));
//		   if(ds_type.contentEquals("uri")){
//			   originURIs.add(datasetId);
//		   }else{
//			   originURIs.addAll(DatasetBrowsing.getMembersByDatasetId(datasetId));//tEntity.getMembersByEntityId(eid));
//		   }
		  
		   /**
		    * 令e1是集合中的某个元素，e是候选的元素
		    * 排序公式rank = sum(0.7*(cooccur(e1,e))+0.3*(包含e1的自定义dataset中含有e的个数/包含e1的dataset个数))
		    */
			try {
				Connection con = DBConnectionFactory.getConnection();
	            PreparedStatement stmt = con.prepareStatement("select dataset_id,doc_id from custom_dataset_doc where dataset_id in (select dataset_id from custom_dataset_doc where doc_id=?)");
	            		//("select identity_id,uri_id from identity_entity where identity_id in (select identity_id from identity_entity where uri_id=?)");
	            HashMap<Integer,HashSet<Integer>> groupHasOrignMap = new HashMap<Integer,HashSet<Integer>>();
				HashMap<Integer,HashSet<Integer>> uriInDatasetMap = new HashMap<Integer, HashSet<Integer>>();
				HashMap<Integer, HashSet<Integer>> cooccurOriginMap = new HashMap<Integer,HashSet<Integer>>();
	            for(Integer uid:originURIs){ 
	            	HashSet<Integer> groupHasOrign = groupHasOrignMap.get(uid);
	            	if(groupHasOrign==null){
	            		groupHasOrign= new HashSet<Integer>();
	            		groupHasOrignMap.put(uid, groupHasOrign);
	            	}
					stmt.setInt(1, uid);
					ResultSet rs = stmt.executeQuery();
					while(rs.next()){
						int datasetID = rs.getInt(1);
						int docID = rs.getInt(2);
						
						 //对于每个原始uri，找到包含它的所有自定义实体，并记录它们，得到公式中的分母
						groupHasOrign.add(datasetID);
						//依次记录这些候选元素所在的文档,加入sameasuri
						if(!originURIs.contains(docID)){
//							if(DatasetBrowsing.getRelatedMygroupDataset("uri", docID, groupID).size()>0)
//								continue;
							HashSet<Integer> dsSet = uriInDatasetMap.get(docID) ;
							if(dsSet==null){
								dsSet  = new HashSet<Integer>();
								uriInDatasetMap.put(docID, dsSet);
							}
							dsSet.add(datasetID) ;
						}
					}
					
					//记录那些与原始URI有sameAs关系的实体
					try {
						HashSet<Integer> cooccurSet = CooccurCache.getInstance().getCooccurURIs(uid);//SameAsCache.getInstance().getSameAsURIs(uid) ;
						for(Integer cooccurID:cooccurSet){
							if(!originURIs.contains(cooccurID)){
//								if(DatasetBrowsing.getRelatedMygroupDataset("uri", cooccurID, groupID).size()>0)
//									continue;
								HashSet<Integer> entitySet = cooccurOriginMap.get(cooccurID) ;
								if(entitySet==null){
									entitySet  = new HashSet<Integer>();
									cooccurOriginMap.put(cooccurID, entitySet);
								}
								entitySet.add(uid);
							}
						}
					} catch (Throwable e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
	            
	            HashSet<Integer> set = new HashSet<Integer>();
	            set.addAll(uriInDatasetMap.keySet()) ;
	            set.addAll(cooccurOriginMap.keySet()) ;
	            ArrayList<RecomdDatasetItem> rSet = new ArrayList<RecomdDatasetItem>();
	            for(Integer uriID:set){
	            	RecomdDatasetItem rItem =new RecomdDatasetItem(uriID,originURIs,cooccurOriginMap,uriInDatasetMap,groupHasOrignMap);
	            	rSet.add(rItem);
	            }
	            
	            Collections.sort(rSet) ;
	            for(RecomdDatasetItem ritem:rSet){
	            	 result.add(ritem);
	            	 if(result.size()>=RECOMMEND_NUM)
	            		 break;
	            }
	            
	            stmt.close();
	            con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return result;
	}
	 public static class RecomdDatasetItem implements Comparable<RecomdDatasetItem>{//=======????
			private int uriID;
			private double score;
			private ArrayList<Boolean> cooccurMap = null;
			private ArrayList<ArrayList<Integer>> groupScoreMap = null;
			private ArrayList<Integer> originArrayList = new ArrayList<Integer>();

			public RecomdDatasetItem(int uriID, HashSet<Integer> origin,
					HashMap<Integer, HashSet<Integer>> cooccurOriginMap,
					HashMap<Integer, HashSet<Integer>> uriInDatasetMap,
					HashMap<Integer, HashSet<Integer>> groupHasOrignMap) {
				this.uriID = uriID;
				this.cooccurMap = new ArrayList<Boolean>();
				this.groupScoreMap = new ArrayList<ArrayList<Integer>>();
				this.originArrayList = new ArrayList<Integer>();
				this.originArrayList.addAll(origin);
				this.score = computeScore(cooccurOriginMap, uriInDatasetMap,
						groupHasOrignMap);
			}
			
			public String getURI(){
				String uri = null;
				try {
					uri = URIIDCache.getInstance().getURI(this.uriID);
				} catch (Throwable e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return uri;
			}
			
			public String getLabel(String lang){
				URIResource r = null;
				try {
					r = ResourceFactory.getInstance().createURIResource(
							this.getURI());
				} catch (Throwable e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				if (DBOperations.getValidStatus(this.getURIID()) != URIResource.VALID
						&& Crawler.getInstance().checkStatus(r) == Crawler.STATUS_UNSUBMITTED) {
					Crawler.getInstance().submitURI(r);
					Crawler.getInstance().promoteWeight(r, Element.LEVEL_1);
					boolean waitflag = true;
					while (waitflag) {
						waitflag = false;
						int status = Crawler.getInstance().checkStatus(r);
						if (status != Crawler.STATUS_DONE) {
							waitflag = true;
							break;
						}
						try {
							Thread.sleep(20);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}

				String label = "";
				try {
					label = URILabelCache.getInstance().getLabel(this.uriID, lang);//URIResource.getURIResourceById(this.uriID).getURI();//
				} catch (Throwable e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				if (label.equals("")) {
					label = URIUtil.getLocalname(r.getURI());
				}
				
				return label;

			}
			
			public int getURIID() {
				return this.uriID;
			}
			
			public ArrayList<Integer> getOrigin() {
				return this.originArrayList;
			}
			
			public ArrayList<Boolean> getCooccurMap(){
				return this.cooccurMap;
			}
			
			public ArrayList<ArrayList<Integer>> getGroupScoreMap(){
				return this.groupScoreMap;
			}
			
			private double getScore(){
				return this.score;
			}

			private double computeScore(
					HashMap<Integer, HashSet<Integer>> cooccurOriginMap,
					HashMap<Integer, HashSet<Integer>> uriInDatasetMap,
					HashMap<Integer, HashSet<Integer>> groupHasOrignMap) {
				double score = 0;
				for (Integer uid : originArrayList) {
					double cooccurScore = 0, groupScore = 0;
					boolean flag = false;
					// compute sameasscore
					if (cooccurOriginMap.containsKey(this.uriID)) {
						if (cooccurOriginMap.get(this.uriID).contains(uid)) {
							flag = true;
							cooccurScore = DatasetBrowsing.COOCCUR_SCORE_WEIGHT;//EntityManagement.SAMEAS_SCORE_WEIGHT;
						}
					}
					cooccurMap.add(flag);

					// compute group score
					int num = 0, groupNum = 0;
					if (groupHasOrignMap.containsKey(uid)) {
						if (uriInDatasetMap.containsKey(this.uriID)) {
							HashSet<Integer> groupSet = groupHasOrignMap.get(uid);
							HashSet<Integer> entitySet = new HashSet<Integer>();
							entitySet.addAll(uriInDatasetMap.get(this.uriID));
							entitySet.retainAll(groupSet);
							num = entitySet.size();
							groupNum = groupSet.size();
							groupScore = DatasetBrowsing.COOCCUR_SCORE_WEIGHT * num//EntityManagement.GROUP_SCORE_WEIGHT * num
									/ groupNum;
						}
					}
					ArrayList<Integer> list = new ArrayList<Integer>();
					list.add(num);
					list.add(groupNum);
					groupScoreMap.add(list);
					score = score + cooccurScore + groupScore;
				}

				return score;
			}

			@Override
			public int compareTo(RecomdDatasetItem arg0) {
				// TODO Auto-generated method stub
				if (this.score < arg0.score)
					return 1;
				else if (this.score == arg0.score)
					return 0;
				return -1;
			}

			@Override
			public int hashCode() {
				final int prime = 31;
				int result = 1;
				result = prime * result + uriID;
				return result;
			}

			@Override
			public boolean equals(Object obj) {
				if (this == obj)
					return true;
				if (obj == null)
					return false;
				if (getClass() != obj.getClass())
					return false;
				RecomdDatasetItem other = (RecomdDatasetItem) obj;
				if (uriID != other.uriID)
					return false;
				return true;
			}
	   }
}
